package com.beauty.product.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.beauty.product.repository.es")
public class ElasticsearchConfig {

    @Value("${spring.elasticsearch.rest.uris}")
    private String elasticsearchUrl;

    @Value("${spring.elasticsearch.rest.username}")
    private String username;

    @Value("${spring.elasticsearch.rest.password}")
    private String password;

    @Bean
    public RestClient restClient() throws Exception {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(username, password));

        String[] hostAndPort = elasticsearchUrl.replace("http://", "")
                .replace("https://", "").split(":");
        String host = hostAndPort[0];
        int port = hostAndPort.length > 1 ? Integer.parseInt(hostAndPort[1]) : 9200;

        // 确定协议
        String protocol = elasticsearchUrl.toLowerCase().startsWith("https") ? "https" : "http";
        System.out.println("正在连接Elasticsearch: " + protocol + "://" + host + ":" + port);

        // 配置IO反应器
        IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
                .setConnectTimeout(30000)
                .setSoTimeout(60000)
                .setIoThreadCount(4)
                .build();

        RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, protocol));

        if (protocol.equals("https")) {
            builder.setHttpClientConfigCallback(httpClientBuilder -> {
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                httpClientBuilder.setSSLContext(createTrustAllSSLContext());
                httpClientBuilder.setSSLHostnameVerifier((hostname, session) -> true);
                httpClientBuilder.setDefaultIOReactorConfig(ioReactorConfig);
                // 增加连接池设置
                httpClientBuilder.setMaxConnTotal(50);
                httpClientBuilder.setMaxConnPerRoute(20);
                return httpClientBuilder;
            });
        } else {
            builder.setHttpClientConfigCallback(httpClientBuilder -> {
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                httpClientBuilder.setDefaultIOReactorConfig(ioReactorConfig);
                // 增加连接池设置
                httpClientBuilder.setMaxConnTotal(50);
                httpClientBuilder.setMaxConnPerRoute(20);
                return httpClientBuilder;
            });
        }

        builder.setRequestConfigCallback(requestConfigBuilder ->
                requestConfigBuilder
                        .setConnectTimeout(30000)
                        .setSocketTimeout(60000));

        // 添加失败重试
        builder.setFailureListener(new RestClient.FailureListener() {
            public void onFailure(HttpHost host) {
                System.out.println("连接失败，节点: " + host + " 不可用");
            }
        });

        return builder.build();
    }

    private SSLContext createTrustAllSSLContext() {
        try {
            // 创建一个信任所有证书的TrustManager（仅用于开发/测试环境！）
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[0];
                        }

                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        }

                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        }
                    }
            };

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            return sslContext;
        } catch (Exception e) {
            throw new RuntimeException("创建SSL上下文失败", e);
        }
    }

    @Bean
    public ElasticsearchTransport elasticsearchTransport() throws Exception {
        return new RestClientTransport(restClient(), new JacksonJsonpMapper());
    }

    @Bean
    public ElasticsearchClient elasticsearchClient() throws Exception {
        return new ElasticsearchClient(elasticsearchTransport());
    }

    @Bean(name = "elasticsearchTemplate")
    @Primary
    public ElasticsearchOperations elasticsearchOperations() throws Exception {
        return new ElasticsearchTemplate(elasticsearchClient());
    }
}
